﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using UnitsAndBuilduings;
using Omron.Framework;
using Omron.Framework.Networking;
using Lidgren.Network;

namespace Omron.Actors
{
    class ResearchFacility : FatherBuilding, IFullSynchronize, IPushUpdate

    {
        public ResearchFacility(BuilduingTypeInfo info, string type, Vector2 loc)
            : base(info, type, loc)
        {
            if ((info.SubTypeCosts.Length != info.SubTypes.Length) || (info.ActionTimes.Length != info.SubTypes.Length))
                throw new Exception("Unit Subtypes must have the same length as SubTypeCosts and as ActionTimes!!");
            
            upgTimes = info.ActionTimes;
            elapsedTime = 0;
            upgrades = new List<string>(info.SubTypes);
            costs = new List<ResourceData>();
            foreach (ResourceCostInfo[] inf in info.SubTypeCosts)
            {
                costs.Add(UnitConverter.CreateResourceData(inf));
            }
            
            menu = new ActorMenu(this);
            composeMenu();
            menu.CommandInvoked += new MenuItemPressed(menu_ItemClicked);
            currentUpgrade = 255;

            IsInvalid = false;
        }

        public void ChekcBuildings()
        {
            foreach (string build in Faction.BuildingsUnlocked)
            {
                if (upgrades.Contains(build))
                {
                    costs.RemoveAt(upgrades.IndexOf(build));
                    upgrades.Remove(build);
                }
            }
        }

        void composeMenu()
        {
            string[] menuStrs = new string[upgrades.Count];
            for (int i = 0; i < menuStrs.Length; i++)
            {
                menuStrs[i] = upgrades[i] + "\n" + createResourceDesc(costs[i]);
            }
            menu.Commands = menuStrs;
        }

        string createResourceDesc(ResourceData cost)
        {
            string str = "";
            if (cost.Crystal != 0)
                str += "Crystal: " + cost.Crystal + "\n";
            if (cost.Metal != 0)
                str += "Metal: " + cost.Metal;
            if (str == "")
                return "free";
            return str;
        }
        

        float[] upgTimes;
        public float elapsedTime;
        List<string> upgrades;
        byte currentUpgrade;
        List<ResourceData> costs;
        ActorMenu menu;
        
        
        void menu_ItemClicked(int itemKey)
        {
            Research(itemKey);
        }
        


        public bool Research(int itemKey)
        {
            if (currentUpgrade == 255)
            {
                if (Faction.Resources >= costs[itemKey])
                {
                    Faction.Resources -= costs[itemKey];
                    currentUpgrade = (byte)itemKey;
                    return true;
                }
            }
            return false;
        }

        public bool IsInvalid { get; set; }

        public override void WriteOutUpdateData(Lidgren.Network.NetOutgoingMessage om)
        {
            base.WriteOutUpdateData(om);

            om.Write(this.elapsedTime);
            om.Write(this.currentUpgrade);

        }
        public override void ReadInUpdateData(Lidgren.Network.NetIncomingMessage im)
        {
            base.ReadInUpdateData(im);

            elapsedTime = im.ReadFloat();
            this.currentUpgrade = im.ReadByte();

            updateMenu();
        }

        void pushUpdate(byte toRemove)
        {
            NetOutgoingMessage update = stage.CreateServerOM();
            if (update != null) //if the server is set
            {
                update.Write(toRemove);
                stage.PushUpdateActor(this, update);
            }
        }
        public void ReadInPushUpdateData(NetIncomingMessage im)
        {
            byte cUpd = im.ReadByte();
            if (cUpd < upgrades.Count || cUpd == 255)
            {
                currentUpgrade = cUpd;
                addUpgrade();
            }
        }

        public override ActorMenu Menu
        {
            get
            {
                if (IsComplete)
                    return menu;
                return base.Menu;
            }
        }

        void updateMenu()
        {
            if (upgrades.Count != menu.Commands.Length)
            {
                composeMenu();
                OnUpdateMenu();
            }
            if (currentUpgrade != 255)
            {
                menu.DisplayBar = true;
                menu.BarValue = (float)elapsedTime / upgTimes[currentUpgrade];
                menu.Info = "current upgrade: " + upgrades[currentUpgrade];
            }
            else
                menu.DisplayBar = false;

            
        }
        public override void UpdateFast(GameTime gameTime)
        {
            base.UpdateFast(gameTime);

            updateMenu();

            if (currentUpgrade != 255)
            {
                elapsedTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (elapsedTime >= upgTimes[currentUpgrade])
                {
                    addUpgrade();
                }
            }
        }

        void addUpgrade()
        {
            elapsedTime = 0;

            Faction.UnlockBuilding(upgrades[currentUpgrade]);
            upgrades.RemoveAt(currentUpgrade);
            costs.RemoveAt(currentUpgrade);
            menu.Info = "";

            pushUpdate(currentUpgrade);
            currentUpgrade = 255;
            updateMenu();
        }
    }
}
